﻿/**
 * \file CarteGrande.cs
 * \brief strategie de creation de carte
 */ 
namespace Implementation
{
	using interfaces;
	using System;
	using System.Collections.Generic;
	using System.Linq;
	using System.Text;
    using Wrapper;
    [SerializableAttribute()]
	public class CarteImpl : StrategieCarte 
	{
		protected List<Case> cases;

        protected List<Unite>[,] posToUnite;

        protected int taille;

        unsafe protected int*** carte_cpp;

		public virtual FabriqueCase fabriqueCase
		{
			get;
			set;
		}

		public virtual List<Case> getCases()
		{
            return cases;
		}

        /**
        * \fn void creerCarte()
        * \ brief crée la carte en utilisant le wrapper
        * \ void
        */
        unsafe public virtual void creerCarte()
		{
            WrapperAlgo algo = new WrapperAlgo();
            int*** c = algo.Map_computeGeneration(taille);
            carte_cpp = c;
            for (int i = 0; i < taille; i++)
            {
                for (int j = 0; j < taille; j++)
                {
                    switch (c[i][j][1])
                    {
                        case (int)WrapperAlgo.ressource.FER:
                            cases.Add(new Fer(avoirCase(c[i][j][0])));break;
                        case (int)WrapperAlgo.ressource.FRUIT:
                            cases.Add(new Fruit(avoirCase(c[i][j][0]))); break;
                        case (int)WrapperAlgo.ressource.RIEN:
                            cases.Add(avoirCase(c[i][j][0])); break;
                    }
                }
            }
		}

        /**
        * \fn int[][] suggestionVille(int x, int y, int pt_mvt)
        * \ brief repère les cases intéréssantes autour d'un enseignant pour installer une ville
        * \ return int[][]
        */
        unsafe public virtual int[][] suggestionVille(int x, int y, int pt_mvt)
        {
            int[][] d = new int[3][];
            d[0] = new int[3];
            d[1] = new int[3];
            d[2] = new int[3];

            for (int i = (x - pt_mvt); i <= (x + pt_mvt); i++)
            {
                for (int j = (y - pt_mvt); j <= (y + pt_mvt); j++)
                {
                    if (i >= 0 && i < taille && j >= 0 && j < taille)
                    {
                        int ressource = calculRessource(i, j);
                        int petite = plusPetiteCase(d);
                        if (d[petite][2] < ressource)
                        {
                            d[petite][0] = i;
                            d[petite][1] = j;
                            d[petite][2] = ressource;
                        }
                    }
                }
            }
            return d;
            /*WrapperAlgo algo = new WrapperAlgo();
            int ** d = algo.Map_computeProposition(x, y, pt_mvt, carte_cpp, taille);
            return d;*/
        }

        /**
        * \fn int plusPetiteCase(int[][] d)
        * \ brief repère la case la moin intéréssante de d et renvoi sa valeur de ressource
        * \ return int
        */
        private int plusPetiteCase(int[][] d)
        {
	        int r = 0;
	        int ressource = d[0][2];
	        for(int i = 1; i < 3; i++)
	        {
		        if(d[i][2] < ressource)
			        r = i;
	        }
	        return r;
        }

        /**
        * \fn int calculRessource(int x, int y)
        * \ brief calcul les ressources à la case localisée à x et y
        * \ return int
        */
        private int calculRessource(int x, int y) {
            int pos = x + (y * taille);
            int ressource = 0;
            int nouriture = getNouriture(x, y);
            int minerai = getMinerai(x, y);
            ressource = nouriture * 2 + minerai;
            return ressource;
        }


        public virtual Case avoirCase(int type)
        {
            switch (type)
            {
                case (int)WrapperAlgo.terrain.MONTAGNE: return fabriqueCase.getMontagne(); 
                case (int)WrapperAlgo.terrain.PLAINE: return fabriqueCase.getPlaine(); 
                case (int)WrapperAlgo.terrain.DESSERT: return fabriqueCase.getDesert();
                default: return fabriqueCase.getPlaine(); 
            }
        }

        public CarteImpl()
        {
            cases = new List<Case>();
            fabriqueCase = new FabriqueCase();
            
		}

		public virtual int getNouriture(int x, int y)
		{
            int pos = x + (y*taille) ;
            return cases[pos].getNouriture();
		}

		public virtual int getMinerai(int x, int y)
		{
            int pos = x + (y * taille);
            return cases[pos].getMinerai();
		}

        public virtual Case getCase(int x, int y)
        {
            int pos = x + (y * taille);
            return cases[pos];
        }

        public virtual int getTaille()
        {
            return taille;
        }

        public virtual List<Unite> getUnites(int x, int y)
        {
            if (x < 0 || x >= taille || y < 0 || y >= taille)
                throw new IndexOutOfRangeException("indice pour acceder à la liste d'unités posToUnite pas bon");
            return posToUnite[x, y];
        }

        public virtual void rajoutUnitPos(int x, int y, Unite u)
        {
            if (posToUnite[x, y] == null)
                posToUnite[x,y] = new List<Unite>();
            if(u!=null)
               posToUnite[x, y].Add(u);
        }

        public virtual void supprUnitPos(int x, int y, Unite u)
        {
            posToUnite[x, y].Remove(u);
        }

        public virtual void deplaceUnit(int xdepart, int ydepart, int xarrive, int yarrive, Unite u)
        {
            supprUnitPos(xdepart, ydepart, u);
            rajoutUnitPos(xarrive, yarrive, u);
        }
	}
}

